<?php

interface serializable {
    public function get_objname();
    public function register_for_remoting();
}
class remote_object implements serializable {
    
}
interface self_class {
    public function get_self_class();
}

class remote_caller_exception extends Exception {
    public $_rc_code = 0, $_rc_msg = '';
    public function __construct() {
        parent::__construct($this->_rc_code, $this->_rc_msg);
    }
}
class object_not_found_rce extends remote_caller_exception {
    public $_rc_code = 10404, $_rc_msg = 'Remote object not found';
}


interface remote_caller {
    
    public function connect($host, $port, $challenge, $response);
    
    public function listen($bind, $port, $challenge, $response);
    
    public function &rcall($objname, $method, $parameters = null);
    
    public function &rget($objname, $property = null);
    
    public function rset($objname, $property, $value);
    
    public function runset($objname, $property);
    
    public function risset($objname, $property);
    
}

class remote_wrapper implements self_class {
    protected $_rwcaller = null, $_rwcache = null, $_rwmethods = array(), $_rwclass = '',
        $_rwobjname = '';
    
    public function __construct(remote_caller &$caller, $objname, $class_name, array $methods) {
        $this->_rwcaller =& $caller;
        $this->_rwmethods = $methods;
        $this->_rwclass = (string)$class_name;
        $this->_rwobjname = (string)$objname;
    }
    
    public function __upgrade(remote_wrapper &$target, $injmeth) {
        call_user_func(array(&$target, $injmeth), $this->_rwcaller, $this->_rwcache,
            $this->_rwobjname, $this->_rwclass, $this->_rwmethods);
    }
    
    public function get_self_class() {
        return $this->_rwclass;
    }
    
    public function __set ( $name, $value )
    {
        $this->_rwcaller->rset($this->_rwobjname, $name, $value);
        $this->_rwcache[$name] = $value;
    }
    public function &__get ( $name )
    {
        if (!isset($this->_rwcache[$name]))
            $this->_rwcache[$name] =& $this->_rwcaller->rget($this->_rwobjname, $name);
        return $this->_rwcache[$name];
    }
    public function __isset ( $name )
    {
        if (isset($this->_rwcache[$name]))
            return true;
        return $this->_rwcache[$name] =& $this->_rwcaller->risset($this->_rwobjname, $name);
    }
    public function __unset ( $name )
    {
        $this->_rwcaller->runset($this->_rwobjname, $name);
        unset($this->_rwcache[$name]);
    }
    public function &__call ( $name, array $arguments )
    {
        if (!isset($this->_rwmethods[$name]))
            throw new Exception ("todo: make this native exception of not having method");
        return $this->_rwcaller->rcall($this->_rwobjname, $name, $arguments);
    }
}

?>